﻿using FluentFTP;
using HalconDotNet;
using LD.Host.项目;
using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Sockets;

namespace LD.Host
{
    public class TcpIpService : ICommunicate
    {
        private TcpService service;
        private ConcurrentDictionary<string, KazamParame> kazams;
        private static object lockIns = new object();
        private static object lockSend = new object();
        private static TcpIpService instance;
        public TcpIpService(int port = 7000)
        {
            kazams = new ConcurrentDictionary<string, KazamParame>();
            service = new TcpService();
            service.Setup(new TouchSocketConfig()//载入配置     
                  .SetListenIPHosts(new IPHost[] { new IPHost($"127.0.0.1:{port}") })//同时监听两个地址, new IPHost(7790)
                  .SetMaxCount(10)
                  .SetThreadCount(100));

            service.Connected += OnConnected;                //有客户端连接
            service.Connecting += (client, e) => { };        //有客户端正在连接
            service.Disconnected += OnDisConnected;          //有客户端断开连接
            service.Received += OnReceived;
        }

        public static TcpIpService getIns
        {
            get
            {
                if (instance == null)
                {
                    lock (lockIns)
                    {
                        if (instance == null)
                            instance = new TcpIpService(7000);
                    }
                }
                return instance;
            }
        }
        private void OnConnected(SocketClient client, EventArgs e)
        {

        }
        private void OnDisConnected(SocketClient client, EventArgs e)
        {
            var slot = kazams.Where(p => p.Value.ClientId == client.ID).FirstOrDefault();
            if (slot.Value != null)
                kazams.TryRemove(slot.Value.Slot, out var parame);
        }
        private void OnReceived(SocketClient client, ByteBlock byteBlock, IRequestInfo requestInfo)
        {
            //从客户端收到信息
            string mes = byteBlock.ToString();
            Console.WriteLine($"已从{client.ID}接收到信息：{mes}");
            var slot = GetSlot(mes);
            if (string.IsNullOrEmpty(slot))
            {
            }
            else
            {
                var parme = new KazamParame()
                {
                    ClientId = client.ID,
                    ClientIp = client.IP,
                    Slot = slot,
                    ClientSendMsg = mes
                };
                kazams.AddOrUpdate(slot, parme, (s, o) => { return parme; });
                Log4.Info($"【{slot}】收到kazam信息");
            }
        }
        /// <summary>
        /// 监控TcpIp是否连接上
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        private bool ClientStateMonitor(string key, int timeout = 3000)
        {
            int reConnectTime = timeout;
            Stopwatch monitor = Stopwatch.StartNew();
            while (CommunicateFactory.Instance.TcpIp[key].Status == Status.失败
                && monitor.ElapsedMilliseconds < reConnectTime)
            {
                Task.Delay(300).Wait();
            }
            return CommunicateFactory.Instance.TcpIp[key].Status == Status.成功;
        }
        private string GetSlot(string msg)
        {
            int sIndex = msg.ToUpper().IndexOf("SLOT");
            if (sIndex < 0)
            {
                Log4.Warr($"【{msg}】穴位无法找到");
                return string.Empty;
            }
            int len = 5;
            return msg.Substring(sIndex - 1, len);
        }
        private void DisConnected(string slot)
        {
            if (string.IsNullOrEmpty(slot))
                return;

            var client = service.GetClients().Where(p => p.ID == kazams[slot].ClientId).FirstOrDefault();
            if (client != null && client.IsClient)
            {
                client.Close();
            }
        }
        public bool ServiceSend_Start(string slot, string msg)
        {
            var SLOT = kazams.Where(p => p.Value.Slot == slot).FirstOrDefault();
            if (SLOT.Value != null)
            {
                service.Send(SLOT.Value.ClientId, msg);


                return true;
            }
            else
                return false;
        }
        public bool ServiceSend_Data(string slot, string msg)
        {
            var SLOT = kazams.Where(p => p.Value.Slot == slot).FirstOrDefault();
            if (SLOT.Value != null)
            {
                service.Send(SLOT.Value.ClientId, msg);
                return true;
            }
            else
                return false;
        }
        public string Name { get; set; } = "KazamService";
        public Status Status { get; set; }

        public event ConnectionStatusDelegate StatusEvent;

        public void Start()
        {
            var s = service.Start();//启动

            StatusEvent?.Invoke(Name, s.ServerState == ServerState.Running ? Status.失败 : Status.成功);
        }
        public void Stop()
        {
            service.Stop();
        }

        /// <summary>
        /// 发送信息至客户端
        /// </summary>
        /// <remarks>如果失败，可重复发送3次</remarks>
        /// <param name="key"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public bool ClientSendMulti(string key, string msg)
        {
            lock (lockSend)
            {
                int reSendCount = 3;
                bool result = false;

                int currentCount = 1;
                while (currentCount < reSendCount)
                {
                    if (ClientStateMonitor(key, 3000))
                    {
                        if (ClientSend(key, msg))
                        {
                            result = true;
                            break;
                        }
                        currentCount++;
                    }
                    else
                    {
                        Log4.Error($"【{key}】通讯连接失败");
                        result = false;
                    }
                }
                return result;
            }
        }
        public bool ClientSend(string key, string msg)
        {
            bool result = false;
            CommunicateFactory.Instance.TcpIp[key].Send(msg);
            var receiverStr = CommunicateFactory.Instance.TcpIp[key].Receive(2000);
            if (receiverStr.IndexOf("Success") >= 0)
                result = true;
            else
            {
                //断开服务端对应的SLOT
                DisConnected(GetSlot(msg));
                Task.Delay(100).Wait();
            }
            return result;
        }
        public KazamParame getSlotParame(string slot)
        {
            if (!kazams.ContainsKey(slot))
                return null;
            return kazams[slot];
        }
        public string Command { get; } = "";
    }
}
